/*
 * @description: 
 * @Author: T.W
 * @Github: https://github.com/TernenceWu0702
 * @Date: 2021-07-23 14:40:14
 * @LastEditors: T.W
 * @LastEditTime: 2021-11-01 17:51:20
 */

/**
 * @description: 节流:当持续触发事件时，保证一定时间段内只调用一次事件处理函数
 * @param {Function} func 执行函数
 * @param {number} delay 节流时间,毫秒
 */
export const throttle = function (func: Function, delay: number) {
    let timer;
    return function () {
        if (!timer) {
            timer = setTimeout(() => {
                func
                // func.apply(this, arguments)
                // 或者直接 func()
                timer = null
            }, delay)
        }
    }
}

/**
 * @description: 防抖:当持续触发事件时，一定时间段内没有再触发事件，事件处理函数才会执行一次
 * @param {Function} fn 执行函数
 * @param {number} wait 防抖时间,毫秒
 */
export const debounce = function (fn: Function, wait: number) {
    let timeout;
    return function () {
        if (timeout !== null) clearTimeout(timeout)// 如果多次触发将上次记录延迟清除掉
        timeout = setTimeout(() => {
            fn()
            timeout = null
        }, wait)
    }
}

/**
 * @description: 阻止冒泡事件
 * @param {*} e
 * @return {*}
 */
export const stopPropagation = (e) => {
    e = e || window.event;
    if (e.stopPropagation) {    // W3C阻止冒泡方法 
        e.stopPropagation();
    } else {
        e.cancelBubble = true; // IE阻止冒泡方法 
    }
}

/**
 * @description: 数据类型判断
 * @param {*} value
 * @return {*}
 */
export const getType = (value) => {
    if (value === null) {
        return value + "";
    }
    // 判断数据是引用类型的情况
    if (typeof value === "object") {
        let valueClass = Object.prototype.toString.call(value),
            type = valueClass.split(" ")[1].split("");
        type.pop();
        return type.join("").toLowerCase();
    } else {
        // 判断数据是基本数据类型的情况和函数的情况
        return typeof value;
    }
}

/**
 * @description: 对象深拷贝
 * @param {*} obj
 * @param {*} hash
 * @return {*}
 */
export const deepClone = (obj, hash = new WeakMap()) => {
    // 日期对象直接返回一个新的日期对象
    if (obj instanceof Date) {
        return new Date(obj);
    }
    //正则对象直接返回一个新的正则对象
    if (obj instanceof RegExp) {
        return new RegExp(obj);
    }
    //如果循环引用,就用 weakMap 来解决
    if (hash.has(obj)) {
        return hash.get(obj);
    }
    // 获取对象所有自身属性的描述
    let allDesc = Object.getOwnPropertyDescriptors(obj);
    // 遍历传入参数所有键的特性
    let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)

    hash.set(obj, cloneObj)
    for (let key of Reflect.ownKeys(obj)) {
        if (typeof obj[key] === 'object' && obj[key] !== null) {
            cloneObj[key] = deepClone(obj[key], hash);
        } else {
            cloneObj[key] = obj[key];
        }
    }
    return cloneObj
}